"""

Native Python implementation that Fetches Logs from an SVN server using Webdav.

Author: Jazz
Last Revision: 10/01/2010
Version: 0.3

Usage: python svnlogfetch.py <srv_address> <Secure Connection [True|False] > <username> <password>
example: python svnlog.py http://svn-py-robot.googlecode.com/svn/trunk/ True jazz.alyxzander 1234qwer


"""

USAGE = 'Usage: python svnlogfetch.py <srv_address> <Secure Connection [True|False] > <username> <password>'


import httplib,sys,re,base64





class WebDavClient:

	DEFAULT_PORT = 80
	DEFAULT_SEC_PORT = 443

	session_headers = dict()

	def __init__(self,address,secure=False,user=None,password=None):
		host,port,uri = self.parse(address)
		self.host= host
		self.uri = uri
		self.port = port
		if port == None:
			if secure == 'True':
				self.port = self.DEFAULT_SEC_PORT
			else:
				self.port = self.DEFAULT_PORT


		if secure == 'True':
	
			self.user = user
			self.password = password
			if user != None:
				self.auth(user,password)
 
			self.conn = httplib.HTTPSConnection(self.host,self.port)
		else:
			self.conn = httplib.HTTPConnection(self.host,self.port)
		
	def auth(self,user,password):
		base64string = base64.encodestring('%s:%s' % (user, password))[:-1]
		authheader =  "Basic %s" % base64string
		self.session_headers['Authorization'] = authheader

	def parse(self,addr):
		proto,host,port,uri = re.search('(.+?://)*([^:/]+)(:\d+)*(/.+)*',addr).groups()
		#print proto,host,port,uri
		return host,port,uri

	def __merge_headers(self,extra_headers):
		# merge Headers
		if self.session_headers == None:
			pass

		else:
			for head in self.session_headers:
				if head not in extra_headers:
					extra_headers[head] = self.session_headers[head]
		return extra_headers

	def connect(self):
		self.conn.connect()
		#print 'Connected'
	

	def getprop(self,prop,uri=None,label=None):
		query =  '<?xml version="1.0" encoding="utf-8"?><propfind xmlns="DAV:">'
		query += '<prop><' + prop + ' xmlns="DAV:"/>'
		query += '<version-name xmlns="DAV:"/></prop></propfind>'
		
		
		extra_headers = dict(Depth=0)
		if label != None:
			extra_headers['Label'] = label
		if uri == None:
			uri = self.uri	

		self.send('PROPFIND',uri,query,extra_headers)
		bOK,data,__ = self.recv()
		#print bOK, data
		if bOK:
			# Parse PropertyValue
			try:
				prop_val = re.search('<lp1:'+prop+'>(?:<D:href>)?(.*?)(?:</D:href>)?</lp1:'+prop+'>',data).group(1)
			except:
				prov_val = None
				sys.stderr.write("Property Not Found")	
		else:
			sys.stderr.write("Communication Error")
			return None		
		return prop_val
	
	def report(self,uri,start_rev,end_rev=0):	
	
		webdav_body =  '<S:log-report xmlns:S="svn:">'
		webdav_body += '<S:start-revision>' + str(start_rev) + '</S:start-revision>'
		webdav_body += '<S:end-revision>'+str(0)+'</S:end-revision>'
		webdav_body += '<S:revprop>svn:author</S:revprop>'
		webdav_body += '<S:revprop>svn:date</S:revprop>'
		webdav_body += '<S:revprop>svn:log</S:revprop>'
		webdav_body += '<S:path></S:path></S:log-report>'

		

		self.send('REPORT',uri,webdav_body)
		bOK,data,__ = self.recv()

		return data
		
		

	def send(self, method,uri,data=None,extra_headers=session_headers):
		if extra_headers == None:
			self.conn.request(method,uri,data)
		else:
			extra_headers = self.__merge_headers(extra_headers)
			self.conn.request(method,uri,data,extra_headers)
		

	"""
		@returns
		(bOk,data,headers)
	""" 
	def recv(self):
		resp = self.conn.getresponse()
		status = resp.status		
		head = resp.getheaders()
		body = resp.read()
		bOK = False		
		#print '----------------',status
		if status/100 == 2:
			bOK=True
		return (bOK, body,head)
		
			
		


def fetch_svn_log(addr,https=False,user=None,password=None):
	
	if https == 'True':
		https == True
	webdav = WebDavClient(addr,secure=https,user=user,password=password)
	webdav.connect()

	vcc_uri = webdav.getprop('version-controlled-configuration')
	version = webdav.getprop('version-name')
	blc_uri = webdav.getprop('baseline-collection',uri=vcc_uri, label=version)
	log = webdav.report(blc_uri,version)
	return log 


if __name__ == '__main__':


	log = ''

	if len(sys.argv) == 2:
		log = fetch_svn_log(sys.argv[1])
	else:
		log = fetch_svn_log(sys.argv[1],sys.argv[2],sys.argv[3],sys.argv[4])

	#print USAGE
	print log

